package model.macro
{
	import util.Random;
	
	/**
	 *
	 */
	public class Player
	{
		static public const NEUTRAL:Player = new Player("Neutral", 0x666666);
		
		private var current_techs:Vector.<model.macro.Tech>;
		private var _hostilePlayers:Vector.<Player>;
		public var color:int;
		public var name:String;
		public var gold:int;
		public var territories:Vector.<model.macro.Territory>;
		
		/**
		 *
		 * @param	name
		 * @param	color
		 */
		public function Player(name:String, color:int)
		{
			this.color = color;
			this.name = name;
			gold = 1000;
			current_techs = new Vector.<Tech>();
			current_techs.push(Tech.IRON_SWORD);
			territories = new Vector.<Territory>();
		}
		
		public function buildFortress(territory:Territory, fortressType:FortressType):void
		{
			if (territory.owner != this)
				throw new Error("Player doesn't own that territory");
			
			if (gold < fortressType.cost)
				throw new Error("Player doesn't have enough gold");
			
			for each (var req:Tech in fortressType.requiredTechs)
			{
				if (current_techs.indexOf(req) < 0)
					throw new Error("Player doesn't have all the required techs to build that");
			}
			
			for each (var building:Building in fortressType.requiredBuildings)
			{
				if (territory.buildings.indexOf(building) < 0)
					throw new Error("Player doesn't have all the required buildings to build that");
			}
			gold -= fortressType.cost;
			territory.fortress = new Fortress(fortressType);
			trace(territory.fortress);
		}
		
		/**
		 * Build a unit in a territory. Throws an error if it can't be built.
		 * @param	territory
		 * @param	weapon
		 * @param	armor
		 */
		public function buildUnit(territory:Territory, weapon:Weapon, armor:Armor):void
		{
			if (territory.owner != this)
				throw new Error("Player doesn't own that territory");
			
			var weapon_researched:Boolean = false;
			var armor_researched:Boolean = false;
			for each (var tech:Tech in current_techs)
			{
				if (weapon_researched && armor_researched)
					break;
				if (tech.allowed_weapons.indexOf(weapon) >= 0)
					weapon_researched = true;
				if (tech.allowed_armors.indexOf(armor) >= 0)
					armor_researched = true;
			}
			if (!weapon_researched)
				throw new Error("That weapon is not researched");
			if (!armor_researched)
				throw new Error("That armor is not researched");
			
			weapon_researched = false;
			armor_researched = false;
			for each (var building:Building in territory.buildings)
			{
				if (weapon_researched && armor_researched)
					break;
				if (building.allowed_weapons.indexOf(weapon) >= 0)
					weapon_researched = true;
				if (building.allowed_armors.indexOf(armor) >= 0)
					armor_researched = true;
			}
			if (!weapon_researched)
				throw new Error("That weapon does not have the required buildings");
			if (!armor_researched)
				throw new Error("That armor does not have the required buildings");
			
			var cost:int = weapon.cost + armor.cost;
			if (cost > gold)
				throw new Error("You can't afford that unit");
			
			territory.units.push(new Unit(this, weapon, armor, 0));
		}
		
		/**
		 * Returns true if the player can build a unit in the territory.
		 * @param	territory
		 * @param	weapon
		 * @param	armor
		 * @return
		 */
		public function canBuildUnit(territory:Territory, weapon:Weapon, armor:Armor):Boolean
		{
			if (territories.indexOf(territories) < 0)
				return false;
			
			var weapon_researched:Boolean = false;
			var armor_researched:Boolean = false;
			for each (var tech:Tech in current_techs)
			{
				if (weapon_researched && armor_researched)
					break;
				if (tech.allowed_weapons.indexOf(weapon) >= 0)
					weapon_researched = true;
				if (tech.allowed_armors.indexOf(armor) >= 0)
					armor_researched = true;
			}
			if (!weapon_researched || !armor_researched)
				return false;
			
			weapon_researched = false;
			armor_researched = false;
			for each (var building:Building in territory.buildings)
			{
				if (weapon_researched && armor_researched)
					break;
				if (building.allowed_weapons.indexOf(weapon) >= 0)
					weapon_researched = true;
				if (building.allowed_armors.indexOf(armor) >= 0)
					armor_researched = true;
			}
			return (weapon_researched && armor_researched);
		}
		
		/**
		 * Research a new tech.
		 * @param	tech
		 */
		public function researchTech(tech:Tech):void
		{
			if (!canResearch(tech))
			{
				throw new Error("YOU CAN'T RESEARCH THAT");
			}
			gold -= tech.cost;
			current_techs.push(tech);
		}
		
		/**
		 * Returns true if the player owns at least one of these buildings.
		 * @param	building
		 * @return
		 */
		public function hasBuilding(building:Building):Boolean
		{
			for each (var territory:Territory in territories)
			{
				if (territory.buildings.indexOf(building) >= 0)
				{
					return true;
				}
			}
			return false;
		}
		
		/**
		 * Returns true if the player can research this tech.
		 * @param	Tech tech
		 * @return
		 */
		public function canResearch(tech:Tech):Boolean
		{
			for each (var prereq:Tech in tech.required_techs)
			{
				if (current_techs.indexOf(prereq) < 0)
				{
					return false;
				}
			}
			for each (var required_building:Building in tech.required_buildings)
			{
				if (!hasBuilding(required_building))
				{
					return false;
				}
			}
			return true;
		}
		
		/**
		 * Returns a vector of all the techs this player can currently research.
		 * @return
		 */
		public function possibleResearch():Vector.<Tech>
		{
			return null;
		}
		
		/**
		 * returns if otherPlayer is hostile to this player
		 * @param	otherPlayer
		 */
		public function isHostile(otherPlayer:Player):Boolean
		{
			return (hostilePlayers.indexOf(otherPlayer) >= 0)
		}
		
		public function toString():String
		{
			return "<Player: " + name + ">";
		}
		
		public function get hostilePlayers():Vector.<Player> 
		{
			if (_hostilePlayers == null)
				_hostilePlayers = new Vector.<Player>;
			return _hostilePlayers;
		}
		
		public function set hostilePlayers(value:Vector.<Player>):void 
		{
			if (_hostilePlayers == null)
				_hostilePlayers = new Vector.<Player>;
			_hostilePlayers = value;
		}
	}
}